from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from uuid import uuid4
from collections import OrderedDict

from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet

from django.conf import settings
from apps import redis_client
from .models import User
from .serializer import UserSerializer, UserSerializerList, UserserializerUpdate
from util.auth import OWNTokenAuthentication
from util.page import MyPageNumberPagination
from util.exception import ValidationError

TOKEN_EXPIRE_TIME = 60 * 60


class LoginViewSet(GenericViewSet):
    '''登录方法'''
    queryset = User.objects.filter(is_delete=False).all()
    serializer_class = UserSerializer

    @action(detail=False, methods=["POST"], url_path="login")
    def post(self, request, *args, **kwargs):
        username = request.data.get('username')
        password = request.data.get('password')
        user = self.get_queryset().filter(username=username, password=password).first()
        if not user:
            raise ValidationError(20002)
        token = self.generate_key(username)
        redis_client.set(username, token, TOKEN_EXPIRE_TIME)
        return Response({"code": 200,
                         "token": token})

    def generate_key(self, username):
        serializer = Serializer(settings.SECRET_KEY, settings.TOKEN_TIME)
        info = {"username": username}
        mi_info = serializer.dumps(info)
        mi_info = mi_info.decode()
        return mi_info

    @action(detail=False, methods=["GET"], url_path="me")
    def login_get(self, request, *args, **kwargs):
        token = request.META.get("HTTP_X_ACCESS_TOKEN")
        yuan_info = self.__de_ser(token)
        username = yuan_info.get("username")
        user = User.objects.filter(username=username, is_active=True).first()
        if user:
            user_id = user.id
            return Response(
                {
                    "code": "success",
                    "result": {
                        "attributes": {},
                        "dimensions": [],
                        "permissions": [],
                        "user": {
                            "id": user_id,
                            "name": "requirement",
                            "type": "user",
                            "username": username},
                    },
                    "status": 200
                }
            )
        else:
            return Response(
                {
                    "code": "failed",
                    "result": {
                        "attributes": {},
                        "dimensions": [],
                        "permissions": [],
                        "user": {
                            "id": "",
                            "name": "requirement",
                            "type": "user",
                            "username": ""},
                    },
                    "status": 403
                }
            )

    def __de_ser(self, mi_info):
        try:
            serializer = Serializer(settings.SECRET_KEY, settings.TOKEN_TIME)
            yuan_info = serializer.loads(mi_info)
        except Exception as e:
            yuan_info = {}
        return yuan_info


class UserViewSet(GenericViewSet):
    authentication_classes = [OWNTokenAuthentication]

    queryset = User.objects.filter(is_delete=False).all()
    serializer_class = UserSerializer

    @action(detail=False, methods=["GET", ], url_path="list")
    def user_list(self, requests, *args, **kwargs):
        username = requests.GET.get("username")
        if username:
            users = User.objects.filter(is_delete=False, username__icontains=username).all()
            if not users:
                users = self.get_queryset()
        else:
            users = self.get_queryset()
        page = MyPageNumberPagination()
        page_usrs = page.paginate_queryset(queryset=users, request=requests, view=self)
        users_ser = UserSerializerList(instance=page_usrs, many=True)
        return Response(self.__get_paginated_response(page, requests, users_ser.data))

    def __get_paginated_response(self, page, request, datas):
        a = OrderedDict([
            ('current', int(page.get_page_number(request, page))),
            ('total', int(page.page.paginator.count)),
            ('pageSize', int(page.get_page_size(request))),
            ('data', datas)
        ])
        return a

    @action(detail=False, methods=["POST"], url_path="create")
    def user_create(self, request, *args, **kwargs):
        id = str(uuid4()).replace("-", "")
        request.data["id"] = id
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            serializer.create(serializer.validated_data)
            return Response({"code": 200, "msg": "添加用户成功"})
        raise ValidationError(20001)

    @action(detail=False, methods=["POST", ], url_path="update")
    def user_update(self, requests, *args, **kwargs):
        data = {}
        data["id"] = requests.data.get("id")
        data["password"] = requests.data.get("password")
        data["is_active"] = requests.data.get("is_active")
        data["is_delete"] = requests.data.get("is_delete")
        serializer = UserserializerUpdate(data=data)
        if serializer.is_valid():
            serializer.update(serializer.validated_data)
            return Response({"code": 200, "msg": "修改成功"})
        else:
            raise ValidationError(20001)

    @action(detail=False, methods=["GET", ], url_path="exit")
    def user_exit(self, request, *args, **kwargs):
        token = request.META.get("HTTP_X_ACCESS_TOKEN")
        if token:
            try:
                yuan_info = self.__de_ser(token)
                redis_client.set("".join(["username_", yuan_info.get("username")]), token, settings.TOKEN_TIME)
                return Response({"code": 200, "msg": "退出成功"})
            except:
                raise ValidationError(40001)

    def __de_ser(self, mi_info):
        try:
            serializer = Serializer(settings.SECRET_KEY, settings.TOKEN_TIME)
            yuan_info = serializer.loads(mi_info)
        except:
            yuan_info = {}
        return yuan_info
